查看原文
其他

滚动截屏,RecyclerView截屏,ScrollView截屏,ListView截屏

BoBoMEe 鸿洋 2019-04-05

每日推荐


如果对自定义AS插件,并希望了解如何做一个多渠道打包这样的有用的插件,推荐:


android插件自定义之多渠道打包插件(支持微信资源混淆andResGuard)

https://www.jianshu.com/p/3e56303fb375


本文作者


作者:BoBoMEe

链接:

http://www.cnblogs.com/BoBoMEe/p/4556917.html

本文由作者授权发布。


在做分享功能的时候,需要截取全屏内容,一屏展示不完的内容,一般我们会用到 ListView ,ScrollView或Recyclerview。


1普通截屏的实现


获取当前Window 的 DrawingCache 的方式,即decorView的DrawingCache。


/**
  * shot the current screen ,with the status but the status is trans *
  *
  * @param ctx current activity   */

 public static Bitmap shotActivity(Activity ctx) {
   View view = ctx.getWindow().getDecorView();
   view.setDrawingCacheEnabled(true);
   view.buildDrawingCache();
   Bitmap bp = Bitmap.createBitmap(view.getDrawingCache(), 0, 0, view.getMeasuredWidth(),
       view.getMeasuredHeight());
   view.setDrawingCacheEnabled(false);
   view.destroyDrawingCache();    return bp;
 }

 

获取当前View的DrawingCache

 

public static Bitmap getViewBp(View v) {
   if (null == v) {
       return null;
   }
   v.setDrawingCacheEnabled(true);
   v.buildDrawingCache();
   if (Build.VERSION.SDK_INT >= 11) {
       v.measure(MeasureSpec.makeMeasureSpec(v.getWidth(),
               MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
               v.getHeight(), MeasureSpec.EXACTLY));
       v.layout((int) v.getX(), (int) v.getY(),
               (int) v.getX() + v.getMeasuredWidth(),
               (int) v.getY() + v.getMeasuredHeight());
   } else {
       v.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
               MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
       v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
   }
   Bitmap b = Bitmap.createBitmap(v.getDrawingCache(), 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
   v.setDrawingCacheEnabled(false);
   v.destroyDrawingCache();
   return b;
}


2开源方案

 

在滚动视图中,如果当前View并没有在视图中全部绘制出来,我们可以利用View的ScrollTo()和ScrollBy()方法来移动画布,同时获取当前View的可视部分的DrawingCache,最后进行拼接得到其Bitmap,参考:PGSSoft/scrollscreenshot@[Github],原理图如下:


https://github.com/PGSSoft/scrollscreenshot

 


3ScrollView截屏


三个截屏中,ScrollView最简单,因为ScrollView只有一个childView,虽然没有全部显示在界面上,但是已经全部渲染绘制,因此可以直接 调用`scrollView.draw(canvas)`来完成截图,


/**
* http://blog.csdn.net/lyy1104/article/details/40048329
*/

public static Bitmap shotScrollView(ScrollView scrollView) {
   int h = 0;
   Bitmap bitmap = null;
   for (int i = 0; i < scrollView.getChildCount(); i++) {
     h += scrollView.getChildAt(i).getHeight();
     scrollView.getChildAt(i).setBackgroundColor(Color.parseColor("#ffffff"));
   }
   bitmap = Bitmap.createBitmap(scrollView.getWidth(), h, Bitmap.Config.RGB_565);
   final Canvas canvas = new Canvas(bitmap);
   scrollView.draw(canvas);
   return bitmap;
}

 

4ListView截屏


而ListView就是会回收与重用Item,并且只会绘制在屏幕上显示的ItemView,根据stackoverflow上大神的建议,采用一个List来存储Item的视图,这种方案依然不够好,当Item足够多的时候,可能会发生oom。


/**
* http://stackoverflow.com/questions/12742343/android-get-screenshot-of-all-listview-items
*/

public static Bitmap shotListView(ListView listview) {
     ListAdapter adapter = listview.getAdapter();
     int itemscount = adapter.getCount();
     int allitemsheight = 0;
     List<Bitmap> bmps = new ArrayList<Bitmap>();
     for (int i = 0; i < itemscount; i++) {
       View childView = adapter.getView(i, null, listview);
       childView.measure(
           View.MeasureSpec.makeMeasureSpec(listview.getWidth(), View.MeasureSpec.EXACTLY),
           View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
       childView.layout(0, 0, childView.getMeasuredWidth(), childView.getMeasuredHeight());
       childView.setDrawingCacheEnabled(true);
       childView.buildDrawingCache();
       bmps.add(childView.getDrawingCache());
       allitemsheight += childView.getMeasuredHeight();
     }
     Bitmap bigbitmap =
         Bitmap.createBitmap(listview.getMeasuredWidth(), allitemsheight, Bitmap.Config.ARGB_8888);
     Canvas bigcanvas = new Canvas(bigbitmap);
     Paint paint = new Paint();
     int iHeight = 0;
     for (int i = 0; i < bmps.size(); i++) {
       Bitmap bmp = bmps.get(i);
       bigcanvas.drawBitmap(bmp, 0, iHeight, paint);
       iHeight += bmp.getHeight();
       bmp.recycle();
       bmp = null;
     }
     return bigbitmap;
}


5RecyclerView截屏


我们都知道,在新的Android版本中,已经可以用RecyclerView来代替使用ListView的场景,相比较ListView,RecyclerView对Item View的缓存支持的更好。可以采用和ListView相同的方案,这里也是在stackoverflow上看到的方案。


/**
* https://gist.github.com/PrashamTrivedi/809d2541776c8c141d9a
*/

public static Bitmap shotRecyclerView(RecyclerView view) {
     RecyclerView.Adapter adapter = view.getAdapter();
     Bitmap bigBitmap = null;
     if (adapter != null) {
       int size = adapter.getItemCount();
       int height = 0;
       Paint paint = new Paint();
       int iHeight = 0;
       final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
       // Use 1/8th of the available memory for this memory cache.
       final int cacheSize = maxMemory / 8;
       LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
       for (int i = 0; i < size; i++) {
         RecyclerView.ViewHolder holder = adapter.createViewHolder(view, adapter.getItemViewType(i));
         adapter.onBindViewHolder(holder, i);
         holder.itemView.measure(
             View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
             View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
         holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(),
             holder.itemView.getMeasuredHeight());
         holder.itemView.setDrawingCacheEnabled(true);
         holder.itemView.buildDrawingCache();
         Bitmap drawingCache = holder.itemView.getDrawingCache();
         if (drawingCache != null) {
           bitmaCache.put(String.valueOf(i), drawingCache);
         }
         height += holder.itemView.getMeasuredHeight();
       }
       bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888);
       Canvas bigCanvas = new Canvas(bigBitmap);
       Drawable lBackground = view.getBackground();
       if (lBackground instanceof ColorDrawable) {
         ColorDrawable lColorDrawable = (ColorDrawable) lBackground;
         int lColor = lColorDrawable.getColor();
         bigCanvas.drawColor(lColor);
       }
       for (int i = 0; i < size; i++) {
         Bitmap bitmap = bitmaCache.get(String.valueOf(i));
         bigCanvas.drawBitmap(bitmap, 0f, iHeight, paint);
         iHeight += bitmap.getHeight();
         bitmap.recycle();
       }
     }
     return bigBitmap;
}


6其他屏幕相关工具


1.获取状态栏高度常见方式

 

/**
* get the height of status *     */

public static int getStatusH(Activity ctx) {
   Rect s = new Rect();
   ctx.getWindow().getDecorView().getWindowVisibleDisplayFrame(s);        return s.top;
}

 

/**
* get the height of status *
*/

public static int getStatusH(Context ctx) {
   int statusHeight = -1;
   try {
       Class<?> clazz = Class.forName("com.android.internal.R$dimen");
       Object object = clazz.newInstance();
       int height = Integer.parseInt(clazz.getField("status_bar_height")
               .get(object).toString());
       statusHeight = ctx.getResources().getDimensionPixelSize(height);
   } catch (Exception e) {
       e.printStackTrace();
   }
   return statusHeight;
}

 

/**
* get the height of status *
*/

public static int getStatusHeight(Activity activity) {
   int resourceId = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
   return resourceId > 0 ? activity.getResources().getDimensionPixelSize(resourceId) : 0;
}

 

2.获取标题栏高度


/**
* get the height of title *
*/

public static int getTitleH(Activity ctx) {
   int contentTop = ctx.getWindow()
           .findViewById(Window.ID_ANDROID_CONTENT).getTop();
   return contentTop - getStatusH(ctx);
}

 

3.获取屏幕宽高


/**
* get the width of screen **
*/

public static int getScreenW(Context ctx) {
   int w = 0;
   if (Build.VERSION.SDK_INT > 13) {
       Point p = new Point();
       ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
               .getDefaultDisplay().getSize(p);
       w = p.x;
   } else {
       w = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
               .getDefaultDisplay().getWidth();
   }
   return w;
}
/**
* get the height of screen *
*/

public static int getScreenH(Context ctx) {
   int h = 0;
   if (Build.VERSION.SDK_INT > 13) {
       Point p = new Point();
       ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
               .getDefaultDisplay().getSize(p);
       h = p.y;
   } else {
       h = ((WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE))
               .getDefaultDisplay().getHeight();
   }
   return h;
}
/**
* 获得屏幕高度
*
* @param context
* @return
*/

public static int getScreenWidth(Context context) {
   WindowManager wm = (WindowManager) context
           .getSystemService(Context.WINDOW_SERVICE);
   DisplayMetrics outMetrics = new DisplayMetrics();
   wm.getDefaultDisplay().getMetrics(outMetrics);
   return outMetrics.widthPixels;
}

 


相关源码:

https://github.com/BoBoMEe/AndroidDev/blob/master/common/common/src/main/java/com/bobomee/android/common/util/ScreenUtil.java


参考:

https://github.com/PGSSoft/scrollscreenshot


刚好之前还推送过webview截屏,这下截屏相关齐活了:




如果你想要跟大家分享你的文章,欢迎投稿~


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存